package com.yxplearn.mybatisplus.deluxe;

import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import org.apache.ibatis.executor.keygen.NoKeyGenerator;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;

public class InsertOrUpdate extends AbstractMethod {

    /**
     * @param methodName 方法名
     * @since 3.5.0
     */
    protected InsertOrUpdate(String methodName) {
        super(methodName);
    }

    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        final String sql = "<script>\nINSERT INTO %s %s VALUES %s ON DUPLICATE KEY UPDATE %s\n</script>";
        final String fieldSql = prepareFieldSql(tableInfo);
        final String valueSql = prepareValuesSqlForMysqlBatch(tableInfo);
        final String updateSql = prepareUpdateSql(tableInfo);
        final String sqlResult = String.format(sql, tableInfo.getTableName(), fieldSql, valueSql, updateSql);
        SqlSource sqlSource = languageDriver.createSqlSource(configuration, sqlResult, modelClass);
        return this.addInsertMappedStatement(mapperClass, modelClass, "insertOrUpdate", sqlSource, new NoKeyGenerator(), null, null);
    }

    private String prepareFieldSql(TableInfo tableInfo) {
        StringBuilder fieldSql = new StringBuilder();
        fieldSql.append("<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\n");
        fieldSql.append(tableInfo.getKeyColumn()).append(",\n");
        tableInfo.getFieldList().forEach(x -> {
            fieldSql.append("<if test=\"").append(x.getProperty()).append(" != null\">");
            fieldSql.append(x.getColumn()).append(",");
            fieldSql.append("</if>\n");
        });
        fieldSql.append("</trim>");
        return fieldSql.toString();
    }

    private String prepareValuesSqlForMysqlBatch(TableInfo tableInfo) {
        final StringBuilder valueSql = new StringBuilder();
        valueSql.append("<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\n");
        valueSql.append("#{").append(tableInfo.getKeyProperty()).append("},\n");
        tableInfo.getFieldList().forEach(x -> {
            valueSql.append("<if test=\"").append(x.getProperty()).append(" != null\">");
            valueSql.append("#{").append(x.getProperty());
            if (x.getTypeHandler() != null) {
                valueSql.append(",typeHandler=").append(x.getTypeHandler().getName());
            }
            valueSql.append("},");
            valueSql.append("</if>\n");
        });
        valueSql.append("\n</trim>");
        return valueSql.toString();
    }

    private String prepareUpdateSql(TableInfo tableInfo) {
        final StringBuilder valueSql = new StringBuilder();
        valueSql.append("<trim prefix=\"\" suffix=\"\" suffixOverrides=\",\">\n");
        tableInfo.getFieldList().forEach(x -> {
            valueSql.append("<if test=\"").append(x.getProperty()).append(" != null\">");
            valueSql.append(x.getColumn()).append(" = #{").append(x.getProperty());
            if (x.getTypeHandler() != null) {
                valueSql.append(",typeHandler=").append(x.getTypeHandler().getName());
            }
            valueSql.append("},");
            valueSql.append("</if>\n");
        });
        valueSql.append("\n</trim>");
        return valueSql.toString();
    }
}
